using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Globalization;
using System.Management;
using System.Runtime.InteropServices;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace UACluster.UAClusterAdmin
{
    public partial class MainForm : Form
    {

        static string nodeListFileName = @"nodes.xml";
        static string configFileName = @"globalConf.xml";

        GlobalConfig globConf = new GlobalConfig();

        public MainForm()
        {
            InitializeComponent();
        }

        private void WakeFunction(string MAC_ADDRESS)
        {
            WOLClass client = new WOLClass();
            client.Connect(new IPAddress(0xffffffff), 0x0009); // port=9
            client.SetClientToBrodcastMode();
            int counter = 0;
            byte[] bytes = new byte[1024];
            for (int y = 0; y < 6; y++)
                bytes[counter++] = 0xFF;
            for (int y = 0; y < 16; y++)
            {
                int i = 0;
                for (int z = 0; z < 6; z++)
                {
                    bytes[counter++] = byte.Parse(MAC_ADDRESS.Substring(i, 2), NumberStyles.HexNumber);
                    i += 2;
                }
            }

            int reterned_value = client.Send(bytes, 1024);
        }

        private void wake_btn_Click(object sender, EventArgs e)
        {
            wakeCheckedNodes();
        }

        ClusterBase mCluster = new ClusterBase();
        
        private void execute_btn_Click(object sender, EventArgs e)
        {
            ExecuteOnChekedNodes(cline_tb.Text.ToString(),false);
        }

        private void saveGlobalConfig(string filename, GlobalConfig gc)
        {
            XmlSerializer xSer = new XmlSerializer(gc.GetType());
            TextWriter tw = new StreamWriter(filename);
            xSer.Serialize(tw, gc);
        }

        private GlobalConfig loadGlobalConfig(string filename)
        {
            XmlSerializer xSer = new XmlSerializer(typeof(GlobalConfig));
            TextReader tr = new StreamReader(filename);
            return (GlobalConfig)xSer.Deserialize(tr);
        }

        private string ExecuteOnChekedNodes(string commandLine, bool apiexec)
        {
            string nodesList = "";
            DataRow[] drs = getFilteredRows("check", "true");
            if (drs == null)
            {
                MessageBox.Show("No Nodes selected!");
                return null;
            }

            foreach (DataRow i in drs)
            {
                nodesList += i["Name"].ToString() + ",";
            }
            nodesList = nodesList.Substring(0, nodesList.Length - 1);
            if (apiexec)
            {
                mCluster.ExecuteCommand(commandLine, nodesList);
            }
            else
            {
                psNodeExec(nodesList, commandLine);
            }

            return nodesList;
        }

        private string ExecuteOnChekedNodes(string commandLine)
        {
            return ExecuteOnChekedNodes(commandLine, true);
        }

        private DataRow[] getFilteredRows(string field, string value)
        {
            string q = field + " = '" + value + "'";
            DataRow[] res = nodesDS.nodeInfo.Select(q);
            if (res.Length == 0)
            {
                return null;
            }
            return res;
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            MainFormInit();
        }

        private void MainFormInit()
        {
            nodesDS.ReadXml(nodeListFileName);
            globConf = loadGlobalConfig(configFileName);


            foreach (Configuration conf in globConf.ConfigurationItems)
            {
                modeSelector_cbb.Items.Add(conf.FriendlyName);
            }
            mCluster.setClusterName(globConf.HeadNodeName);
            mCluster.setClusterLogin(globConf.DefaultAdminLogin);
            mCluster.setClusterPassword(globConf.DefaultAdminPassword);
        }

        private string parseMAC(string MAC)
        {
            return MAC.Replace("-", "");
        }

        private void wakeCheckedNodes()
        {
            DataRow[] drs = getFilteredRows("check", "true");

            if (drs == null) return;
            foreach (DataRow i in drs)
            {
                WakeFunction(parseMAC(i["MAC"].ToString()));
            }
        }

        private string psNodeExec(string nodesList, string cmd)
        {
            CMD c = new CMD();
            string res;
            res = c.Run(@"psexec.exe", @"-d \\" + nodesList + " " + cmd);
            return res; 
        }

        private void shut_btn_Click(object sender, EventArgs e)
        {
            string command = globConf.ConfigurationItems[0].ShutdownCommand;
            ExecuteOnChekedNodes(command, false);
        }

        private void hiber_btn_Click(object sender, EventArgs e)
        {
            string command = globConf.ConfigurationItems[0].HibernateCommand;
            ExecuteOnChekedNodes(command, false);
        }

        private void restart_btn_Click(object sender, EventArgs e)
        {
            string command = globConf.ConfigurationItems[0].RestartCommand;
            ExecuteOnChekedNodes(command, false);
        }

        private void save_btn_Click(object sender, EventArgs e)
        {
            nodesDS.WriteXml(nodeListFileName);
        }

        private void chMode_btn_Click(object sender, EventArgs e)
        {
            object s = modeSelector_cbb.SelectedItem;
            if (s != null)
            {
                switchClusterConfig(modeSelector_cbb.Items.IndexOf(s));
            }
            else MessageBox.Show("Select a mode!");
        }

        private bool replaceMBRFile(string parsedMAC, int configID)
        {
            string tftpRootDir = Directory.GetCurrentDirectory() + @"\tftproot";
            string fileName = parsedMAC + @".mbr";
            string srcPath = tftpRootDir + @"\" + configID.ToString()+ @"\" + fileName;
            string dstPath = tftpRootDir + @"\" + fileName;
            if (File.Exists(srcPath))
            {
                File.Copy(srcPath, dstPath, true);
                return true;
            }
                return false;
        }

        private void switchClusterConfig (int configID)
        {
            DataRow[] drs = getFilteredRows("check", "true");

            foreach (DataRow i in drs)
            {
                if (replaceMBRFile(parseMAC(i["MAC"].ToString()), configID))
                {
                    i["Status"] = globConf.ConfigurationItems[configID].FriendlyName.ToUpper();
                }
                else
                {
                    //ERRORR
                    i["Status"] = "";
                    MessageBox.Show("MBR File not found for " + i["Name"].ToString());
                }
                
            }

        }

        // Auto/timer functions

        private void autoClusterOn(int hour, int minute)
        {
            TimeZone localZone = TimeZone.CurrentTimeZone;
            TimeSpan localTimeSpan = localZone.GetUtcOffset(new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day));

            DateTime localTime = DateTime.UtcNow;
            localTime = localTime.Add(localTimeSpan);

            if (localTime.Hour == hour && localTime.Minute == minute)
            {
                // Start Cluster

                timer1.Enabled = false;
                timer2.Enabled = true;
                //MessageBox.Show("Cluster Starting");
                
                //switchClusterMode(ClusterMode.Cluster);
                switchClusterConfig(0);
                wakeCheckedNodes();
                //switchClusterMode("0");

            }
        }

        private void autoClusterOFF(int hour, int minute)
        {
            TimeZone localZone = TimeZone.CurrentTimeZone;
            TimeSpan localTimeSpan = localZone.GetUtcOffset(new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day));

            DateTime localTime = DateTime.UtcNow;
            localTime = localTime.Add(localTimeSpan);

            if (localTime.Hour == hour && localTime.Minute == minute)
            {
                // Stop Cluster

                timer2.Enabled = false;
                timer1.Enabled = true;

                switchClusterConfig(1);
                string command = globConf.ConfigurationItems[0].HibernateCommand;
                ExecuteOnChekedNodes(command, false);
                //ExecuteOnChekedNodes("shutdown -h", false);
                //ExecuteOnChekedNodes("shutdown -f -r -t 00", false);

                //MessageBox.Show("Cluster Stoping");

                //switchClusterMode(ClusterMode.Client1);
                //ExecuteOnChekedNodes(clusterConf.HibernateCommand);
                

            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            autoClusterOn(decimal.ToInt32(onHourPick.Value), decimal.ToInt32(onMinutePick.Value));
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            autoClusterOFF(decimal.ToInt32(offHourPick.Value), decimal.ToInt32(offMinutePick.Value));
        }

        private void timers_chk_CheckedChanged(object sender, EventArgs e)
        {
            if (timers_chk.Checked)
            {
                timer1.Enabled = true;
                //MessageBox.Show("Timers Started!");
            }
            else
            {
                timer1.Enabled = false;
                timer2.Enabled = false;
                //MessageBox.Show("Timers Stopped!");
            }
        }

    }
}